package cn.jbolt.core.model.base;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.setting.Setting;
import cn.jbolt.core.annotation.JBoltAutoCache;
import cn.jbolt.core.annotation.TableBind;
import cn.jbolt.core.base.JBoltIDGenMode;
import cn.jbolt.core.base.config.JBoltConfig;
import cn.jbolt.core.base.config.JBoltExtendDatabaseConfig;
import cn.jbolt.core.consts.JBoltConst;
import cn.jbolt.core.db.datasource.JBoltDataSourceUtil;
import cn.jbolt.core.db.datasource.JBoltDatasource;
import cn.jbolt.core.db.sql.DBType;
import cn.jbolt.core.db.sql.Sql;
import cn.jbolt.core.gen.JBoltField;
import cn.jbolt.core.kit.JBoltSaasTenantKit;
import cn.jbolt.core.util.JBoltArrayUtil;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.Model;

import java.lang.reflect.Method;
import java.util.*;

/**
 * JBoltModel配置
 *
 * @ClassName: JBoltModelConfig
 * @author: JFinal学院-小木 QQ：909854136
 * @date: 2021年3月14日
 *
 */
@SuppressWarnings({ "rawtypes" })
public enum JBoltModelConfig {
	me;
	protected static final Log LOG = Log.getLog(JBoltModelConfig.class);
	private static Map<Class<? extends Model>, TableBind> tableBindMap = new HashMap<Class<? extends Model>, TableBind>();
	private static Map<Class<? extends Model>, JBoltAutoCache> autoCacheMap = new HashMap<Class<? extends Model>, JBoltAutoCache>();
	private static Map<Class<? extends Model>, String> datasourceMap = new HashMap<Class<? extends Model>, String>();
	private static Map<Class<? extends Model>, String> databaseMap = new HashMap<Class<? extends Model>, String>();
	private static Map<Class<? extends Model>, String> schemaMap = new HashMap<Class<? extends Model>, String>();
	private static Map<Class<? extends Model>, String> dbTypeMap = new HashMap<Class<? extends Model>, String>();
	private static Map<Class<? extends Model>, String> tableNameMap = new HashMap<Class<? extends Model>, String>();
	private static Map<String,Class<? extends Model>> modelClassMap = new HashMap<String,Class<? extends Model>>();
	private static Map<Class<? extends Model>, String> primaryKeyMap = new HashMap<Class<? extends Model>, String>();
	private static Map<Class<? extends Model>, String[]> compositePrimaryKeyMap = new HashMap<Class<? extends Model>, String[]>();
	private static Map<Class<? extends Model>, String> idGenModeMap = new HashMap<Class<? extends Model>, String>();
	private static Map<Class<? extends Model>, String> idSeqMap = new HashMap<Class<? extends Model>, String>();
	private static Map<Class<? extends Model>, Boolean> separateMap = new HashMap<Class<? extends Model>, Boolean>();
	private static Set<Class<? extends Model>> innerSeparateSet = new HashSet<Class<? extends Model>>();
	private static Set<Class<? extends Model>> projectSeparateSet = new HashSet<Class<? extends Model>>();
	private static Map<Class<? extends Model>, Map<String,String>> modelColumnToAttrMap = new HashMap<Class<? extends Model>, Map<String,String>>();
	private static Map<Class<? extends Model>, Map<String,String>> modelAttrToColumnMap = new HashMap<Class<? extends Model>, Map<String,String>>();

	/**
	 * 获取项目saas配置的租户加入分表序列的models
	 * @return
	 */
	public Set<Class<? extends Model>> getProjectSaasConfigSeparateModelSet(){
		return projectSeparateSet;
	}
	/**
	 * 添加配置
	 *
	 * @param modelClass
	 * @param databaseName
	 * @param schema
	 */
	public void addConfig(Class<? extends Model> modelClass,String databaseName,String schema) {
		addTableBind(modelClass,databaseName,schema);
		addAutoCache(modelClass);
	}

	/**
	 * 添加表绑定配置
	 * @param modelClass
	 * @param databaseName
	 * @param schema
	 */
	public void addTableBind(Class<? extends Model> modelClass,String databaseName,String schema) {
		if (!modelClass.isAnnotationPresent(TableBind.class)) {
			String msg = String.format("[%s]中未设置TableBind注解，无法初始化其配置", modelClass);
			LOG.error(msg);
			throw new RuntimeException(msg);
		}
		TableBind tableBind = modelClass.getAnnotation(TableBind.class);
		if (StrKit.isBlank(tableBind.table())) {
			String msg = String.format("[%s]中@TableBind未设置table属性，无法完成表与Model映射", modelClass);
			LOG.error(msg);
			throw new RuntimeException(msg);
		}

		// datasource 数据源配置
		addDatasource(modelClass, tableBind.dataSource());
		// database 数据库名
		addDatabase(modelClass, databaseName);
		// database 数据库 schema sqlserver专用
		addSchema(modelClass, schema);
		// table表名 配置数据库类型
		addTableName(modelClass, tableBind.table());
		// dbtype 配置数据库类型
		addDbType(modelClass, tableBind.dataSource());
		// primarykey 配置主键
		addPrimaryKey(modelClass, tableBind.primaryKey());
		// id策略
		addIdGenMode(modelClass, tableBind.dataSource(), tableBind.idGenMode());
		// id seq str
		addIdSequenceStr(modelClass, tableBind.idSequence());
		// separate
		addSeparate(modelClass, tableBind.separate());
		// 处理attr column 映射
		addColumnAttrMap(modelClass);
		// 加入map
		tableBindMap.put(modelClass, tableBind);
	}

	/**
	 * 添加id主键 自增序列配置
	 *
	 * @param modelClass
	 * @param idSequence
	 */
	private void addIdSequenceStr(Class<? extends Model> modelClass, String idSequence) {
		String dbType = dbTypeMap.get(modelClass);
		// 如果不是空并且不是default 说明是自己指定的 直接赋值即可
		if (StrKit.notBlank(idSequence) && !JBoltConst.JBOLT_ID_SEQUENCE_DEFAULT.equals(idSequence)) {
			switch (dbType) {
			case DBType.POSTGRESQL:
				idSeqMap.put(modelClass, "nextval('" + idSequence + "')");
				break;
			case DBType.ORACLE:
				idSeqMap.put(modelClass, idSequence + ".nextval");
				break;
			case DBType.DM:
				idSeqMap.put(modelClass, idSequence + ".nextval");
				break;
			}
			return;
		}
		// 判断是不是序列类型ID 然后按照内置规则处理
		String idGenMode = idGenModeMap.get(modelClass);
		if (JBoltIDGenMode.SEQUENCE.equalsIgnoreCase(idGenMode)
				|| JBoltIDGenMode.SEQUENCE_LONG.equalsIgnoreCase(idGenMode)) {
			String tableName = tableNameMap.get(modelClass);
			switch (dbType) {
			case DBType.POSTGRESQL:
				idSeqMap.put(modelClass, "nextval('" + tableName + "_idsq')");
				break;
			case DBType.ORACLE:
				idSeqMap.put(modelClass, tableName + "_idsq.nextval");
				break;
			case DBType.DM:
				idSeqMap.put(modelClass, tableName + "_idsq.nextval");
				break;
			}
		}
	}

	/**
	 * 添加自动缓存配置
	 *
	 * @param modelClass
	 */
	public void addAutoCache(Class<? extends Model> modelClass) {
		if (modelClass.isAnnotationPresent(JBoltAutoCache.class)) {
			autoCacheMap.put(modelClass, modelClass.getAnnotation(JBoltAutoCache.class));
		}
	}

	/**
	 * 配置主键和复合主键
	 *
	 * @param modelClass
	 * @param primaryKey
	 */
	private void addPrimaryKey(Class<? extends Model> modelClass, String primaryKey) {
		if (StrKit.isBlank(primaryKey)) {
			LOG.warn("[{}]中@TableBind未设置primaryKey,默认值 id", modelClass);
			primaryKeyMap.put(modelClass, JBoltConst.DEFAULT_PRIMARY_KEY_NAME);
			return;
		}
		if (!primaryKey.contains(",")) {
			primaryKeyMap.put(modelClass, primaryKey);
			return;
		}
		// 复合多主键处理
		String[] compositePrimaryKeys = JBoltArrayUtil.from3(primaryKey, ",");
		if (compositePrimaryKeys == null || compositePrimaryKeys.length == 0) {
			String msg = "addPrimaryKey compositePrimaryKeys is null";
			LOG.error(msg);
			throw new RuntimeException(msg);
		}
		compositePrimaryKeyMap.put(modelClass, compositePrimaryKeys);
	}

	/**
	 * 获取id序列名称
	 *
	 * @param modelClass
	 * @return
	 */
	public String getIdSequenceStr(Class<? extends Model> modelClass) {
		return idSeqMap.get(modelClass);
	}

	/**
	 * 配置model映射的表的名字
	 *
	 * @param modelClass
	 * @param table
	 */
	private void addTableName(Class<? extends Model> modelClass, String table) {
		tableNameMap.put(modelClass, table);
		modelClassMap.put(table,modelClass);
	}
	/**
	 * 配置数据库名称
	 *
	 * @param modelClass
	 * @param database
	 */
	private void addDatabase(Class<? extends Model> modelClass, String database) {
		databaseMap.put(modelClass, StrKit.defaultIfBlank(database, JBoltConfig.MAIN_DB_NAME));
	}
	/**
	 * 配置数据库Schema 目前只有sqlserver用到 默认dbo
	 *
	 * @param modelClass
	 * @param schema
	 */
	private void addSchema(Class<? extends Model> modelClass, String schema) {
		schemaMap.put(modelClass, StrKit.defaultIfBlank(schema, JBoltConst.JBOLT_SQLSERVER_SCHEMA_DEFAULT));
	}

	/**
	 * 配置数据源配置name
	 *
	 * @param modelClass
	 * @param dataSource
	 */
	private void addDatasource(Class<? extends Model> modelClass, String dataSource) {
		if (StrKit.isBlank(dataSource)) {
			LOG.warn("[{}]中@TableBind未设置datasource,默认使用了main主数据源", modelClass);
			datasourceMap.put(modelClass, DbKit.MAIN_CONFIG_NAME);
			return;
		}
		datasourceMap.put(modelClass, dataSource);
	}

	/**
	 * 添加数据库类型配置
	 *
	 * @param modelClass
	 * @param dataSource
	 */
	private void addDbType(Class<? extends Model> modelClass, String dataSource) {
		if (StrKit.isBlank(dataSource) || DbKit.MAIN_CONFIG_NAME.equals(dataSource)) {
			dbTypeMap.put(modelClass, JBoltConfig.MAIN_DB_TYPE);
			return;
		}
		Setting setting = JBoltExtendDatabaseConfig.me().getSetting();
		if (setting == null) {
			dbTypeMap.put(modelClass, JBoltConfig.MAIN_DB_TYPE);
			return;
		}

		dbTypeMap.put(modelClass,
				setting.getStr(JBoltConst.CONFIG_PROPERTIES_KEY_DB_TYPE, dataSource, JBoltConfig.MAIN_DB_TYPE));
	}

	/**
	 * 添加attr column 映射
	 * @param modelClass
	 */
	private void addColumnAttrMap(Class<? extends Model> modelClass) {
		List<Method> methods = ClassUtil.getPublicMethods(modelClass, method->method.isAnnotationPresent(JBoltField.class));
		if(methods == null || methods.size() == 0){
			throw new RuntimeException("modelClass:"+modelClass.getName()+" 的baseModel中的getter方法没有加注解：JBoltField");
		}
		JBoltField jboltField;
		Map<String,String> attrToColumnMap = new HashMap<>();
		Map<String,String> columnToAttrMap = new HashMap<>();
		for(Method m:methods){
			jboltField = m.getAnnotation(JBoltField.class);
			attrToColumnMap.put(jboltField.name(),jboltField.columnName());
			columnToAttrMap.put(jboltField.columnName(),jboltField.name());
		}
		modelAttrToColumnMap.put(modelClass,attrToColumnMap);
		modelColumnToAttrMap.put(modelClass,columnToAttrMap);
	}

	/**
	 * 获取一个model的所有Java属性名称对应数据库列名的map
	 * @param modelClass
	 * @return
	 */
	public Map<String,String> getModelAttrToColumnMap(Class<? extends Model> modelClass){
		return modelAttrToColumnMap.get(modelClass);
	}

	/**
	 * 获取一个model的所有数据库列名对应Java属性名称的map
	 * @param modelClass
	 * @return
	 */
	public Map<String,String> getModelColumnToAttrMap(Class<? extends Model> modelClass){
		return modelColumnToAttrMap.get(modelClass);
	}

	/**
	 * 从model中通过attr直接拿到数据库对应的字段名称
	 * @param modelClass
	 * @param attrName
	 * @return
	 */
	public String modelAttrToColumn(Class<? extends Model> modelClass,String attrName){
		Map<String,String> map = getModelAttrToColumnMap(modelClass);
		if(map == null){
			throw new RuntimeException("modelClass:"+modelClass.getName()+" 没有初始化对应的attrToColumnMap");
		}
		return map.get(attrName);
	}

	/**
	 * 从model中通过数据库字段名称直接拿到对应的java属性名称
	 * @param modelClass
	 * @param columnName
	 * @return
	 */
	public String modelColumnToAttr(Class<? extends Model> modelClass,String columnName){
		Map<String,String> map = getModelColumnToAttrMap(modelClass);
		if(map == null){
			throw new RuntimeException("modelClass:"+modelClass.getName()+" 没有初始化对应的columnToAttrMap");
		}
		return map.get(columnName);
	}


	/**
	 * 添加数据库类型配置
	 *
	 * @param modelClass
	 * @param separate
	 */
	private void addSeparate(Class<? extends Model> modelClass, boolean separate) {
		if(innerSeparateSet.contains(modelClass) || projectSeparateSet.contains(modelClass)) {
			//如果已经存在就是优先级最高
			separateMap.put(modelClass, true);
		}else {
			separateMap.put(modelClass, separate);
		}
	}

	/**
	 * 添加可以分表的models
	 * @param modelClasses
	 */
	@SuppressWarnings("unchecked")
	public void addInnerSeparateModels(Class<? extends Model>... modelClasses) {
		if(modelClasses!=null && modelClasses.length>0) {
			for(Class<? extends Model> clazz:modelClasses) {
				addInnerSeparateModel(clazz);
			}
		}
	}
	/**
	 * 添加可以分表的models
	 * @param modelClasses
	 */
	@SuppressWarnings("unchecked")
	public void addProjectSeparateModels(Class<? extends Model>... modelClasses) {
		if(modelClasses!=null && modelClasses.length>0) {
			for(Class<? extends Model> clazz:modelClasses) {
				addProjectSeparateModel(clazz);
			}
		}
	}

	/**
	 * 添加一个分表Modelclass jbolt_core内部自带model
	 * @param modelClass
	 */
	public void addInnerSeparateModel(Class<? extends Model> modelClass) {
		if(!modelClass.isAnnotationPresent(TableBind.class)) {
			throw new RuntimeException("modelClasses:"+modelClass.getName()+"未设置TableBind注解");
		}
		LOG.debug("正在将Model[{}]加入分表生成序列....",modelClass.getName());
		innerSeparateSet.add(modelClass);
	}

	/**
	 * 添加一个实际二开项目的分表Modelclass
	 * @param modelClass
	 */
	public void addProjectSeparateModel(Class<? extends Model> modelClass) {
		if(!modelClass.isAnnotationPresent(TableBind.class)) {
			throw new RuntimeException("modelClasses:"+modelClass.getName()+"未设置TableBind注解");
		}
		LOG.debug("正在将Model[{}]加入分表生成序列....",modelClass.getName());
		projectSeparateSet.add(modelClass);
	}

	/**
	 * 添加来自saas config文件中的配置 分表的packages
	 * @param configPackagesStr
	 */
	public void addProjectSeparateModelFromSaasConfigPackages(String configPackagesStr) {
		if(StrKit.isBlank(configPackagesStr)) {return;}
		LOG.debug("正在处理saas config 加入分表生成序列packages....");
		String[] configPackages = JBoltArrayUtil.from3(configPackagesStr, ",");
		if(configPackages.length == 0) {
			LOG.debug("saas config 加入分表生成序列packages 配置为空 不予处理....");
			return;
		}
		String[] carr = null;
		for(String config:configPackages) {
			if(StrKit.isBlank(config)) {continue;}
			if(config.contains(":")) {
				carr = config.split(":");
				if(StrKit.isBlank(carr[0])) {
					continue;
				}
				if(carr.length==1) {
					addProjectSeparateModelFromPackage(carr[0], false);
				}else {
					addProjectSeparateModelFromPackage(carr[0], Boolean.parseBoolean(carr[1]));
				}
			}else{
				addProjectSeparateModelFromPackage(config, false);
			}
		}



	}
	/**
	 * 添加哪个包下的models 进入saas分表序列
	 * @param packageName
	 * @param mustModelTableBindSeparateIsTrue
	 */
	@SuppressWarnings("unchecked")
	public void addProjectSeparateModelFromPackage(String packageName, boolean mustModelTableBindSeparateIsTrue) {
		LOG.debug("正在扫描包[{}]下的Model....",packageName);
		Set<Class<?>> modelClasses = ClassUtil.scanPackage(packageName, filter->{
			boolean hasTableBind = filter.isAnnotationPresent(TableBind.class);
			if(!hasTableBind) {return false;}
			if(mustModelTableBindSeparateIsTrue) {
				return filter.getAnnotation(TableBind.class).separate();
			}
			return true;
		});
		if(modelClasses!=null) {
			modelClasses.forEach(mc->{
				addProjectSeparateModel((Class<? extends Model>)mc);
			});
		}
		LOG.debug("扫描包[{}]下的Model 完成....",packageName);
	}

	/**
	 * 添加可以分表的models
	 * @param mustModelTableBindSeparateIsTrue 是否必须指定model的tablebind上separate设置为true
	 * @param packages
	 */
	public void addProjectSeparateModelFromPackages(boolean mustModelTableBindSeparateIsTrue,String... packages) {
		if(packages==null || packages.length==0) {
			return;
		}
		LOG.debug("正在扫描需要指定包里需要增加到租户分表models");
		for(String pk:packages) {
			addProjectSeparateModelFromPackage(pk,mustModelTableBindSeparateIsTrue);
		}
	}

	/**
	 * 添加主键生成策略配置
	 *
	 * @param modelClass
	 * @param datasource
	 * @param idGenMode
	 */
	private void addIdGenMode(Class<? extends Model> modelClass, String datasource, String idGenMode) {
		// 如果设置全局强制统一ID策略 就直接使用强制策略
		if (StrKit.notBlank(JBoltConfig.FORCE_CAST_GLOBAL_ID_GEN_MODE)) {
			idGenModeMap.put(modelClass, JBoltConfig.FORCE_CAST_GLOBAL_ID_GEN_MODE);
			return;
		}
		// 首先判断是不是主数据源 是主数据源 配置文件里配置主数据源前置锁定所有表id策略一致
		if (DbKit.MAIN_CONFIG_NAME.equals(datasource)) {
			if (StrKit.notBlank(JBoltConfig.MAIN_FORCE_CAST_ALL_ID_GEN_MODE)) {
				idGenModeMap.put(modelClass, JBoltConfig.MAIN_FORCE_CAST_ALL_ID_GEN_MODE);
				return;
			}
			// 如果tableBind缺失了 就使用主数据源默认策略
			if (StrKit.isBlank(idGenMode)) {
				// 如果没有设置默认主键策略 tabelBind上还没设置 那只能默认auto
				if (StrKit.notBlank(JBoltConfig.MAIN_ID_GEN_MODE)) {
					idGenModeMap.put(modelClass, JBoltConfig.MAIN_ID_GEN_MODE);
					return;
				}
				idGenModeMap.put(modelClass, JBoltConfig.GLOBAL_DEFAULT_ID_GEN_MODE);
				return;
			}
			idGenModeMap.put(modelClass, idGenMode);
			return;
		}

		// 扩展数据源
		Setting settings = JBoltExtendDatabaseConfig.me().getSetting();
		if (settings != null) {
			Setting setting = settings.getSetting(datasource);
			if (setting != null) {
				// 说明找到了扩展配置数据源的配置信息 检测是否存在强制策略
				String extendForceCastAllIdGenMode = setting.get("force_cast_all_id_gen_mode");
				if (StrKit.notBlank(extendForceCastAllIdGenMode)) {
					idGenModeMap.put(modelClass, extendForceCastAllIdGenMode);
					return;
				}
				// 如果没有强制策略就判断 tableBind缺失了 就使用此扩展数据源默认策略
				if (StrKit.isBlank(idGenMode)) {
					String extendIdGenMode = setting.get("id_gen_mode");
					if (StrKit.notBlank(extendIdGenMode)) {
						idGenModeMap.put(modelClass, extendIdGenMode);
						return;
					}
					// 如果没有配置数据源默认策略就使用全局默认策略
					idGenModeMap.put(modelClass, JBoltConfig.GLOBAL_DEFAULT_ID_GEN_MODE);
					return;
				}

			}
		}

		if (StrKit.isBlank(idGenMode)) {
			idGenModeMap.put(modelClass, JBoltConfig.GLOBAL_DEFAULT_ID_GEN_MODE);
			return;
		}
		idGenModeMap.put(modelClass, idGenMode);
	}

	/**
	 * 获取主键
	 *
	 * @param modelClass
	 * @return
	 */
	public String getPrimaryKey(Class<? extends Model> modelClass) {
		return primaryKeyMap.get(modelClass);
	}

	/**
	 * 获取符合主键
	 *
	 * @param modelClass
	 * @return
	 */
	public String[] getCompositePrimaryKeys(Class<? extends Model> modelClass) {
		return compositePrimaryKeyMap.get(modelClass);
	}

	/**
	 * 获取数据库名称
	 *
	 * @param modelClass
	 * @return
	 */
	public String getDatabase(Class<? extends Model> modelClass) {
		return databaseMap.get(modelClass);
	}
	/**
	 * 获取数据库schema
	 *
	 * @param modelClass
	 * @return
	 */
	public String getSchema(Class<? extends Model> modelClass) {
		return schemaMap.get(modelClass);
	}
	/**
	 * 获取表名
	 *
	 * @param modelClass
	 * @return
	 */
	public String getTableName(Class<? extends Model> modelClass) {
		return tableNameMap.get(modelClass);
	}
	/**
	 * 获取表名 带数据库前缀
	 *
	 * @param modelClass
	 * @return
	 */
	public String getTableNameWithDatabase(Class<? extends Model> modelClass) {
		return processTableName(modelClass);
	}


	/**
	 * 处理tableName
	 *
	 * @param modelClass
	 * @return
	 */
	public String processTableName(Class<? extends Model> modelClass) {
		Objects.requireNonNull(modelClass, "modelClass is null");
		String tableName = getTableName(modelClass);
		if (!JBoltConfig.SAAS_ENABLE || !JBoltModelConfig.me.isSeparate(modelClass) || !JBoltSaasTenantKit.me.isOk()) {
			return processTableName(modelClass, tableName);
		}
		String tenantId = JBoltSaasTenantKit.me.getIdToStr();
		if (StrKit.isBlank(tenantId)) {
			throw new RuntimeException("租户ID获取失败");
		}
		return processSaasTenantTableName(modelClass, tableName,tenantId);
	}

	/**
	 * 处理租户数据源表名
	 * @param modelClass
	 * @param tableName
	 * @param tenantId
	 * @return
	 */
	private String processSaasTenantTableName(Class<? extends Model> modelClass, String tableName, String tenantId) {
		tableName = tableName + Sql.KEY_TABLENAME_ENDLINE +tenantId;
		return processTenantDatabaseAndTableName(tableName);
	}

	/**
	 * 处理是否需要拼接数据库名
	 *
	 * @param modelClass
	 * @param tableName
	 * @return
	 */
	private String processTableName(Class<? extends Model> modelClass, String tableName) {
		return processDatabaseAndTableName(modelClass, tableName);
	}

	/**
	 * 根据数据库类型处理名称
	 *
	 * @param name
	 * @return
	 */
	public String processNameByDbType(String dbType,String name) {
		switch (dbType) {
			case DBType.MYSQL:
				if(name.contains(Sql.KEY_MYSQL_SINGLE_QUOTES)){
					return name;
				}
				return Sql.KEY_MYSQL_SINGLE_QUOTES + name + Sql.KEY_MYSQL_SINGLE_QUOTES;
			case DBType.SQLSERVER:
				if(name.contains(Sql.KEY_SQUARE_BRACKETS_LEFT) || name.contains(JBoltConst.JBOLT_SQLSERVER_SCHEMA_DEFAULT)){
					return name;
				}
				return Sql.KEY_SQUARE_BRACKETS_LEFT + name + Sql.KEY_SQUARE_BRACKETS_RIGHT;
			case DBType.POSTGRESQL:
			case DBType.ORACLE:
				if(JBoltConfig.ORACLE_SQL_QUOTATION_MARK_ENABLE){
					if(name.contains(Sql.KEY_QUOTATION_MARKS)){
						return name;
					}
					return Sql.KEY_QUOTATION_MARKS + name + Sql.KEY_QUOTATION_MARKS;
				}
				return name;
			case DBType.DM:
				if(name.contains(Sql.KEY_QUOTATION_MARKS)){
					return name;
				}
				return Sql.KEY_QUOTATION_MARKS + name + Sql.KEY_QUOTATION_MARKS;
			default:
				break;
		}
		return name;
	}

	/**
	 * 获得数据库+表名 全名
	 * 根据数据库类型返回格式
	 *
	 * @param modelClass
	 * @param tableName
	 * @return
	 */
	public String processDatabaseAndTableName(Class<? extends Model> modelClass, String tableName) {
		if(tableName.contains(".")){
			return tableName;
		}
		Objects.requireNonNull(modelClass, "modelClass is null");
		//拿到数据库名称
		String database = getDatabase(modelClass);
		if (StrKit.isBlank(database)) {
			throw new RuntimeException("数据源[" + getDataSourceConfigName(modelClass) + "]"  + "数据库配置文件未设置db_name");
		}
		String dbType = getDbType(modelClass);
		if (StrKit.isBlank(dbType)) {
			throw new RuntimeException("数据源[" + getDataSourceConfigName(modelClass) + "]"  + "数据库配置文件未设置db_type");
		}
		String formatDbName = processNameByDbType(dbType,database);
		if (DBType.isSqlServer(dbType)) {
			//拿到数据库名称
			String schema = JBoltModelConfig.me.getSchema(modelClass);
			formatDbName = formatDbName + Sql.KEY_DOT + StrKit.defaultIfBlank(schema, JBoltConst.JBOLT_SQLSERVER_SCHEMA_DEFAULT);
		}
		String formatTableName = processNameByDbType(dbType,tableName);
		return formatDbName + Sql.KEY_DOT + formatTableName;
	}


	/**
	 * 获得数据库+表名 全名
	 * 根据数据库类型返回格式
	 *
	 * @param tableName
	 * @return
	 */
	private String processTenantDatabaseAndTableName(String tableName) {
		//拿到数据库名称
		JBoltDatasource dataSource = JBoltDataSourceUtil.me.getJBoltDatasource(JBoltConfig.SAAS_TENANT_DATASOURCE_CONFIG_NAME);
		if(dataSource == null){
			throw new RuntimeException("数据源配置【"+JBoltConfig.SAAS_TENANT_DATASOURCE_CONFIG_NAME+"】加载异常 无法获取jboltDataSource");
		}
		String database = dataSource.getDbName();
		if (StrKit.isBlank(database)) {
			throw new RuntimeException("数据源[" + dataSource.getName() + "]"  + "数据库配置文件未设置db_name");
		}
		String dbType = dataSource.getDbType();
		if (StrKit.isBlank(dbType)) {
			throw new RuntimeException("数据源[" + dataSource.getName() + "]"  + "数据库配置文件未设置db_type");
		}
		String formatDbName = processNameByDbType(dbType,database);
		if (DBType.isSqlServer(dbType)) {
			//拿到数据库名称
			String schema = dataSource.getDbSchema();
			formatDbName = formatDbName + Sql.KEY_DOT + StrKit.defaultIfBlank(schema, JBoltConst.JBOLT_SQLSERVER_SCHEMA_DEFAULT);
		}
		String formatTableName = processNameByDbType(dbType,tableName);
		return formatDbName + Sql.KEY_DOT + formatTableName;
	}








	/**
	 * 获取表是否分表
	 * @param modelClass
	 * @return
	 */
	public boolean isSeparate(Class<? extends Model> modelClass) {
		return separateMap.get(modelClass);
	}

	/**
	 * 获取数据源配置名
	 *
	 * @param modelClass
	 * @return
	 */
	public String getDataSourceConfigName(Class<? extends Model> modelClass) {
		return datasourceMap.get(modelClass);
	}

	/**
	 * 获取数据库类型
	 *
	 * @param modelClass
	 * @return
	 */
	public String getDbType(Class<? extends Model> modelClass) {
		return dbTypeMap.get(modelClass);
	}

	/**
	 * 获取id策略
	 *
	 * @param modelClass
	 * @return
	 */
	public String getIdGenMode(Class<? extends Model> modelClass) {
		return idGenModeMap.get(modelClass);
	}

	/**
	 * 获取autoCache配置
	 *
	 * @param modelClass
	 * @return
	 */
	public JBoltAutoCache getJBoltAutoCache(Class<? extends Model> modelClass) {
		return autoCacheMap.get(modelClass);
	}

	/**
	 * 获取tableBind配置
	 *
	 * @param modelClass
	 * @return
	 */
	public TableBind getTableBind(Class<? extends Model> modelClass) {
		return tableBindMap.get(modelClass);
	}

	/**
	 * 判断如果没有处理过配置就主动处理
	 *
	 * @param modelClass
	 */
	public void addConfigIfNotExist(Class<? extends Model> modelClass) {
		if (!tableBindMap.containsKey(modelClass)) {
			addConfig(modelClass,null,JBoltConst.JBOLT_SQLSERVER_SCHEMA_DEFAULT);
		}
	}

	/**
	 * 是否是主数据源下的表
	 * @param modelClass
	 * @return
	 */
	public boolean isMainDataSource(Class<? extends Model> modelClass){
		String datasourceConfigName = getDataSourceConfigName(modelClass);
		return DbKit.MAIN_CONFIG_NAME.equalsIgnoreCase(datasourceConfigName);
	}

	/**
	 * 通过表明获取modelClass
	 * @param tableName
	 * @return
	 */
	public Class<? extends Model> getModelClassByTable(String tableName) {
		return modelClassMap.get(tableName);
	}
}
